<!doctype html>
<html lang="zh-CN"><head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
    <title>薛尧的博客</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="" />

    
    
    
    <link rel="stylesheet" href="../../../css/theme.min.css">

    
    
    
    
    <link rel="stylesheet" href="../../../css/custom.min.css">
    

    
</head>
<body>
        <div id="content" class="mx-auto"><header class="container mt-sm-5 mt-4 mb-4 mt-xs-1">
    <div class="row">
        
        <div class="col-sm-4 col-12 text-sm-right text-center pt-sm-4">
            <a href="../../../" class="text-decoration-none">
                <img id="home-image" class="rounded-circle"
                    
                        src="https://ueyao.github.io/image-hosting/blog/avatar.png"
                    
                />
            </a>
        </div>
        <div class="col-sm-8 col-12 text-sm-left text-center">
        
            <h2 class="m-0 mb-2 mt-4">
                <a href="../../../" class="text-decoration-none">
                    
                        薛尧
                    
                </a>
            </h2>
            <p class="text-muted mb-1">
                
                    Java Developer | Short Video Creator
                
            </p>
            <ul id="nav-links" class="list-inline mb-2">
                
                
                    <li class="list-inline-item">
                        <a class="badge badge-white " href="../../../about/" title="关于">关于</a>
                    </li>
                
                    <li class="list-inline-item">
                        <a class="badge badge-white " href="../../../post/" title="文章">文章</a>
                    </li>
                
                    <li class="list-inline-item">
                        <a class="badge badge-white " href="../../../categories/" title="分类">分类</a>
                    </li>
                
            </ul>
            <ul id="nav-social" class="list-inline">
                
                    <li class="list-inline-item mr-3">
                        <a href="http://github.com/flowstone" target="_blank">
                            <i class="fab fa-github fa-1x text-muted"></i>
                        </a>
                    </li>
                
                    <li class="list-inline-item mr-3">
                        <a href="mailto:xueyao.me#gmail.com" target="_blank">
                            <i class="fas fa-at fa-1x text-muted"></i>
                        </a>
                    </li>
                
            </ul>
        </div>
    </div>
    <hr />
</header>
<div class="container">
    <div class="pl-sm-2">
        <div class="mb-3">
            <h3 class="mb-0">React中如何实现文件上传功能</h3>
            
            <small class="text-muted">发布于 2021-01-04</small>
        </div>

        <article>
            <h3 id="场景描述">场景描述</h3>
<p>在前端页面中，经常会使用到文件上传功能，我们如何实现上传功能呢？</p>
<h3 id="开发环境">开发环境</h3>
<ul>
<li>React ^16.12.0</li>
<li>Ant Design ^5.0.12</li>
<li>SpringBoot 2.3.0</li>
</ul>
<h3 id="页面实现文件上传">页面实现文件上传</h3>
<p>首先我们要用到Ant框架中自带的上传组件Upload，代码如下所示</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-tsx" data-lang="tsx"><span style="display:flex;"><span><span style="color:#75715e">//index.tsx
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">props</span> <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//组件的名字，调用接口时传递的名称
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">name</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;file&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//上传前的操作
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">beforeUpload</span><span style="color:#f92672">:</span> (<span style="color:#a6e22e">file</span>: <span style="color:#66d9ef">any</span>, <span style="color:#a6e22e">fileList</span>: <span style="color:#66d9ef">any</span>) <span style="color:#f92672">=&gt;</span> {
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">&#39;file, fileList&#39;</span>, <span style="color:#a6e22e">file</span>, <span style="color:#a6e22e">fileList</span>);
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">//上传的文件列表  
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>      <span style="color:#a6e22e">setFileList</span>(<span style="color:#a6e22e">fileList</span>);
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">//返回false 代表暂停上传 需要我们自己实现
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>      <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>;
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//下面代码是上传按钮
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>&lt;<span style="color:#f92672">Upload</span> {<span style="color:#a6e22e">...props</span>}&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">Button</span> <span style="color:#a6e22e">icon</span><span style="color:#f92672">=</span>{&lt;<span style="color:#f92672">UploadOutlined</span> /&gt;}&gt;<span style="color:#960050;background-color:#1e0010">选择</span>&lt;/<span style="color:#f92672">Button</span>&gt;
</span></span><span style="display:flex;"><span> &lt;/<span style="color:#f92672">Upload</span>&gt;
</span></span></code></pre></div><p>上述代码，可以实现一个上传功能，但是还没有和后端有交互，效果图如下
<img src="https://ueyao.github.io/image-hosting/blog/2021/1/20210121213849699_1070937386.png" alt=""></p>
<p>我们再添加一个上传按钮，来和后端交互，代码如下所示</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-tsx" data-lang="tsx"><span style="display:flex;"><span><span style="color:#75715e">//index.tsx
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>&lt;<span style="color:#f92672">Col</span> <span style="color:#a6e22e">style</span><span style="color:#f92672">=</span>{{ <span style="color:#a6e22e">margin</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;10px 20px&#39;</span> }}&gt;
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#f92672">Upload</span> {<span style="color:#a6e22e">...props</span>}&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">Button</span> <span style="color:#a6e22e">icon</span><span style="color:#f92672">=</span>{&lt;<span style="color:#f92672">UploadOutlined</span> /&gt;}&gt;<span style="color:#960050;background-color:#1e0010">选择</span>&lt;/<span style="color:#f92672">Button</span>&gt;
</span></span><span style="display:flex;"><span>  &lt;/<span style="color:#f92672">Upload</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">Col</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">Col</span> <span style="color:#a6e22e">style</span><span style="color:#f92672">=</span>{{ <span style="color:#a6e22e">margin</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;10px 20px&#39;</span> }}&gt;
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#f92672">Button</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;primary&#34;</span> <span style="color:#a6e22e">onClick</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">uploadOnClick</span>}&gt;
</span></span><span style="display:flex;"><span>    <span style="color:#960050;background-color:#1e0010">上传</span>
</span></span><span style="display:flex;"><span>  &lt;/<span style="color:#f92672">Button</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">Col</span>&gt;
</span></span></code></pre></div><p>上传按钮绑定了一个事件uploadOnClick，如下所示</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-tsx" data-lang="tsx"><span style="display:flex;"><span><span style="color:#75715e">//index.tsx
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//文件列表
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">const</span> [<span style="color:#a6e22e">fileList</span>, <span style="color:#a6e22e">setFileList</span>] <span style="color:#f92672">=</span> <span style="color:#a6e22e">useState</span>([]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">uploadOnClick</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">async</span> () <span style="color:#f92672">=&gt;</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//表单上传需要创建一个FormData对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">formData</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">FormData</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">fileList</span>.<span style="color:#a6e22e">forEach</span>(<span style="color:#a6e22e">file</span> <span style="color:#f92672">=&gt;</span> {
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">formData</span>.<span style="color:#a6e22e">append</span>(<span style="color:#e6db74">&#39;file&#39;</span>, <span style="color:#a6e22e">file</span>);
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">&#39;formData:&#39;</span>, <span style="color:#a6e22e">formData</span>.<span style="color:#66d9ef">get</span>(<span style="color:#e6db74">&#39;file&#39;</span>));
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//调用上传接口
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">result</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">await</span> <span style="color:#a6e22e">upload</span>(<span style="color:#a6e22e">formData</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">&#39;data:&#39;</span>, <span style="color:#a6e22e">result</span>);
</span></span><span style="display:flex;"><span>  };
</span></span></code></pre></div><p>前端调用的上传接口，如下所示</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ts" data-lang="ts"><span style="display:flex;"><span><span style="color:#75715e">//service.ts
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">export</span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">upload</span> <span style="color:#f92672">=</span> (<span style="color:#a6e22e">data</span>: <span style="color:#66d9ef">any</span>) <span style="color:#f92672">=&gt;</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">//此处对axios做了一层封装
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">post</span>(<span style="color:#e6db74">&#39;/smsTemp/upload&#39;</span>, <span style="color:#a6e22e">data</span>);
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span><span style="color:#75715e">//----------- 上面代码也可以这样写 ------
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">export</span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">upload</span> <span style="color:#f92672">=</span> (<span style="color:#a6e22e">data</span>: <span style="color:#66d9ef">any</span>) <span style="color:#f92672">=&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Promise</span>(<span style="color:#a6e22e">resolve</span> <span style="color:#f92672">=&gt;</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">axios</span>(<span style="color:#e6db74">&#39;/smsTemp/upload&#39;</span>, {
</span></span><span style="display:flex;"><span>          <span style="color:#a6e22e">method</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;POST&#39;</span>,
</span></span><span style="display:flex;"><span>          <span style="color:#a6e22e">data</span>,
</span></span><span style="display:flex;"><span>        })
</span></span><span style="display:flex;"><span>          .<span style="color:#a6e22e">then</span>((<span style="color:#a6e22e">r</span>: <span style="color:#66d9ef">any</span>) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">resolve</span>(<span style="color:#a6e22e">r</span>))
</span></span><span style="display:flex;"><span>          .<span style="color:#66d9ef">catch</span>((<span style="color:#a6e22e">e</span>: <span style="color:#66d9ef">any</span>) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">error</span>(<span style="color:#a6e22e">e</span>));
</span></span><span style="display:flex;"><span>     });
</span></span></code></pre></div><p>前端代码，写得差不多了，可以写后端接口了</p>
<h3 id="后端实现文件上传">后端实现文件上传</h3>
<p>控制器Controller的编写，代码如下所示</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//SmsTemplateController.java</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@PostMapping</span>(<span style="color:#e6db74">&#34;/upload&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> R <span style="color:#a6e22e">upload</span>(MultipartFile file) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> smsTemplateService.<span style="color:#a6e22e">upload</span>(file);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>具体实现，代码如下所示</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//SmsTemplateServiceImpl.java</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> R <span style="color:#a6e22e">upload</span>(MultipartFile uploadFile) {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//获得文件名        </span>
</span></span><span style="display:flex;"><span>    String name <span style="color:#f92672">=</span> uploadFile.<span style="color:#a6e22e">getName</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//获得文件全名，带后缀</span>
</span></span><span style="display:flex;"><span>    String fullName <span style="color:#f92672">=</span> uploadFile.<span style="color:#a6e22e">getOriginalFilename</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//获得文件后缀名</span>
</span></span><span style="display:flex;"><span>    String suffix <span style="color:#f92672">=</span> fullName.<span style="color:#a6e22e">substring</span>(fullName.<span style="color:#a6e22e">lastIndexOf</span>(<span style="color:#e6db74">&#34;.&#34;</span>));
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//此处写死上传路径，可以根据要求自定义</span>
</span></span><span style="display:flex;"><span>    String pathFile <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;/Users/simonxue/Developer/Temp/&#34;</span><span style="color:#f92672">+</span>name <span style="color:#f92672">+</span> suffix;
</span></span><span style="display:flex;"><span>    File file <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> File(pathFile);
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">try</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//上传文件</span>
</span></span><span style="display:flex;"><span>        uploadFile.<span style="color:#a6e22e">transferTo</span>(file);
</span></span><span style="display:flex;"><span>    } <span style="color:#66d9ef">catch</span> (IOException e) {
</span></span><span style="display:flex;"><span>        e.<span style="color:#a6e22e">printStackTrace</span>();
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> R.<span style="color:#a6e22e">ofSuccess</span>(<span style="color:#e6db74">&#34;上传文件成功&#34;</span>, pathFile);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div>
        </article>
    </div>

    <div id="disqus_thread"></div>
<script>
    window.disqus_config = function () {
    
    
    
    };
    (function() {
        if (["localhost", "127.0.0.1"].indexOf(window.location.hostname) != -1) {
            document.getElementById('disqus_thread').innerHTML = 'Disqus comments not available by default when the website is previewed locally.';
            return;
        }
        var d = document, s = d.createElement('script'); s.async = true;
        s.src = '//' + "xie-yao-de-bo-ke" + '.disqus.com/embed.js';
        s.setAttribute('data-timestamp', +new Date());
        (d.head || d.body).appendChild(s);
    })();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="https://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>

            </div>
        </div><footer class="text-center pb-1">
    <small class="text-muted">
        
        &copy; Copyright 2024
        
        |
        <a href="https://beian.miit.gov.cn/" target="_blank">苏ICP备14012079号</a>
        <br />
        由 <a href="https://gohugo.io/" target="_blank">Hugo</a> 强力驱动
        | 主题 <a href="https://github.com/austingebauer/devise" target="_blank">Devise</a>
        <br />

    </small>
</footer></body>
</html>
